package br.com.foxinline.servico.historico;

import br.com.foxinline.enums.Caracterizacao;
import br.com.foxinline.enums.Cobertura;
import br.com.foxinline.enums.Comando;
import br.com.foxinline.enums.DominioTerra;
import br.com.foxinline.enums.EstadoConservacao;
import br.com.foxinline.enums.Estrutura;
import br.com.foxinline.enums.Fachada;
import br.com.foxinline.enums.FatorLocalizacao;
import br.com.foxinline.enums.Forro;
import br.com.foxinline.enums.InstSanitaria;
import br.com.foxinline.enums.InstalacoesEletricas;
import br.com.foxinline.enums.Ocupacao;
import br.com.foxinline.enums.Patrimonio;
import br.com.foxinline.enums.Pedologia;
import br.com.foxinline.enums.Piso;
import br.com.foxinline.enums.Posicao;
import br.com.foxinline.enums.RevExterno;
import br.com.foxinline.enums.SituacaoImovel;
import br.com.foxinline.enums.SituacaoTerreno;
import br.com.foxinline.enums.TipoConstrucao;
import br.com.foxinline.enums.TipoDocumentoImovel;
import br.com.foxinline.enums.TipoImovel;
import br.com.foxinline.enums.TipoPropriedade;
import br.com.foxinline.enums.TipoTitulo;
import br.com.foxinline.enums.Topografia;
import br.com.foxinline.enums.UsoImovel;
import br.com.foxinline.enums.Utilizacao;
import br.com.foxinline.enums.Vinculo;
import br.com.foxinline.generico.ServicoHistoricoGenerico;
import br.com.foxinline.modelo.Anexo;
import br.com.foxinline.modelo.Dimensao;
import br.com.foxinline.modelo.Endereco;
import br.com.foxinline.modelo.Imovel;
import br.com.foxinline.modelo.Proprietario;
import br.com.foxinline.modelo.Usuario;
import br.com.foxinline.servico.AnexoServico;
import br.com.foxinline.servico.DimensaoServico;
import br.com.foxinline.servico.EnderecoServico;
import br.com.foxinline.servico.ImovelServico;
import br.com.foxinline.servico.ProprietarioServico;
import br.com.foxinline.servico.UsuarioServico;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.Query;

/**
 *
 * @author laverson
 */
@Stateless
public class ImovelHistoricoServico extends ServicoHistoricoGenerico<Imovel> {

    @EJB
    UsuarioServico usuarioServico;
    @EJB
    ImovelServico imovelServico;
    @EJB
    ProprietarioServico proprietarioServico;
    @EJB
    EnderecoServico enderecoServico;
    @EJB
    DimensaoServico dimensaoServico;
    @EJB
    AnexoServico anexoServico;
    private Imovel atual;

    public ImovelHistoricoServico() {
        super(Imovel.class);
    }

    public List<Imovel> history(Long id) {

        List<Object[]> history = findQueryHistory(id);

        this.atual = imovelServico.find(id);
//        this.atual.setCreateAt(null);
//        this.atual.setDataAtualizacao(null);
//        this.atual.setDate_create(null);
//
//        if (this.atual.getAnnex() != null && this.atual.getAnnex().isEmpty()) {
//            this.atual.setAnnex(null);
//        }
//        if (this.atual.getAnnexCroquis() != null && this.atual.getAnnexCroquis().isEmpty()) {
//            this.atual.setAnnexCroquis(null);
//        }

        List<Imovel> historicos = new ArrayList<Imovel>();
        Imovel historico;

        for (Object[] object : history) {

            historico = novaEntidade(object);

            comparar(historico, this.atual, false);

            if (!historico.equals(this.atual) && isAdd()) {

                if (historico.getUsuarioAtualizacao() != null && historico.getUsuarioAtualizacao().getId() != null) {

                    historico.setUsuarioAtualizacao(this.usuarioServico.find(historico.getUsuarioAtualizacao().getId()));

                } else if (this.atual.getUsuarioAtualizacao() != null) {

                    historico.setUsuarioAtualizacao(this.usuarioServico.find(this.atual.getUsuarioAtualizacao().getId()));
                }

                historico.setDataAtualizacao((Date) object[101]);

                historicos.add(historico);

                setAdd(false);
            }

            this.atual = historico;
        }

        return historicos;
    }

    /**
     * Atribui os valores contidos em object[] para os atributos equivalentes a
     * entidade Imovel
     *
     * <br/> <p> <b>Author:</b> Diego Laverson</P>
     *
     * @param object
     * @return
     */
    private Imovel novaEntidade(Object[] object) {
        Imovel historico = new Imovel();

        historico.setId((Long) object[0]);
//        historico.setBolsaFamilia((Boolean) object[1]);
        historico.setBook((String) object[2]);
        historico.setBook_notary((String) object[3]);
        historico.setCalcamento((Boolean) object[4]);

        setarCaracterizacao(historico, object[5]);
        setarCobertura(historico, object[6]);

        historico.setColetaLixo((Boolean) object[7]);

        setarComando(historico, object[8]);

        historico.setComplementBook((String) object[9]);
        historico.setComplementLeaf((String) object[10]);

        setarComposicaoFamiliar(historico, object[11]);

        historico.setCoordX((Double) object[12]);
        historico.setCoordY((Double) object[13]);
//        historico.setCreateAt((Date) object[14]);
        historico.setCreateAt(this.atual.getCreateAt());
//        historico.setDate_create((Date) object[15]);
        historico.setDate_create(this.atual.getDate_create());
        historico.setDataAforamento((Date) object[16]);

        setarDominioTerra(historico, object[17]);

        historico.setEnviado((Boolean) object[18]);

        setarEstadoConservacao(historico, object[19]);
        setarEstrutura(historico, object[20]);
        setarFachada(historico, object[21]);
        // fatorLocalização object[22] depreciado
        setarForro(historico, object[23]);

        historico.setFrente((String) object[24]);
        historico.setFrenteMedindo((BigDecimal) object[25]);
        historico.setFrenteRua((String) object[26]);

        historico.setFundo((String) object[27]);
        historico.setFundoMedindo((BigDecimal) object[28]);
        historico.setFundoRua((String) object[29]);

        historico.setGroupCreate((String) object[30]);
        historico.setGroupUpdate((String) object[31]);

        historico.setIluminacaoPublica((Boolean) object[32]);

        historico.setInscricaoCadastralD((Integer) object[33]);
        historico.setInscricaoCadastralLote((Integer) object[34]);
        historico.setInscricaoCadastralQuadra((Integer) object[35]);
        historico.setInscricaoCadastralS((Integer) object[36]);
        historico.setInscricaoCadastralUnid((Integer) object[37]);

        historico.setIsentoIptu((Boolean) object[38]);
        historico.setIsentoTsu((Boolean) object[39]);

        setarInstalacaoSanitaria(historico, object[40]);
        setarInstalacaoEletrica(historico, object[41]);

        historico.setLadoDireito((String) object[42]);
        historico.setLadoDireitoMedindo((BigDecimal) object[43]);
        historico.setLadoDireitoRua((String) object[44]);

        historico.setLadoEsquerdo((String) object[45]);
        historico.setLadoEsquerdoMedindo((BigDecimal) object[46]);
        historico.setLadoEsquerdoRua((String) object[47]);

        historico.setLeaf((String) object[48]);
        historico.setLeaf_notary((String) object[49]);

        historico.setLimpezaPublica((Boolean) object[50]);
//        historico.setMinhaCasaMinhaVida((Boolean) object[51]);

        historico.setNotary_plowed((String) object[52]);
        historico.setNumOrder((Integer) object[53]);

        historico.setNumeroAforamento((String) object[54]);
        historico.setObs((String) object[56]);

        setarOcupacao(historico, object[57]);

        historico.setPagaIptu((Boolean) object[58]);

        setarPatrimonio(historico, object[59]);
        setarPedologia(historico, object[60]);
        setarPiso(historico, object[61]);
        setarPosicao(historico, object[62]);

        historico.setPrevious_record((String) object[63]);
        historico.setRegImovel((Boolean) object[64]);

        setarRendaFamiliar(historico, object[65]);
        setarRevestimentoExterno(historico, object[66]);

        historico.setRip((String) object[67]);
        historico.setRipNomeCadastrado((Boolean) object[68]);

        setarSituacaoTerreno(historico, object[69]);

        historico.setStatus((Boolean) object[70]);
//        historico.setTempoMoradia((String) object[71]);
//        historico.setTempoMoradiaMunicipio((String) object[72]);

        setarTipoConstrucao(historico, object[73]);
        setarTipoDocumentoImovel(historico, object[74]);

        historico.setTitle((String) object[75]);
        historico.setTitle_notary((String) object[76]);
        historico.setTitularFalecido((Boolean) object[77]);

        setarTopografia(historico, object[78]);
        setarTipoPropriedade(historico, object[79]);
        setarTipoImovel(historico, object[80]);
        setarTipoTitulo(historico, object[81]);
        setarUsoImovel(historico, object[82]);
        setarUtilizacao(historico, object[83]);

//        historico.setValorBolsaFamilia((Double) object[84]);

        setarVinculoTitularRip(historico, object[86]);
        setarDimensoes(historico, object[87]);
        setarEnderecoCorrespondencia(historico, object[88]);
        setarEnderecoImovel(historico, object[89]);
        setarImovel(historico, object[90]);
        setarSituacaoImovel(historico, object[92]);
        setarFatorLocalizacao(historico, object[93]);

        setarLocalizacao(historico, object[93]);

        Date data_final = (Date) object[101];

        setarProprietariosImovel(this.atual.getId(), historico, data_final);

        if (object[99] != null) {
            historico.setUsuarioAtualizacao(new Usuario());
            historico.getUsuarioAtualizacao().setId((Long) object[99]);
        }

        historico.setCoordenadas(this.atual.getCoordenadas());
        historico.setVersao(this.atual.getVersao());
        historico.setDataAtualizacao(this.atual.getDataAtualizacao());
        historico.setMoradores(this.atual.getMoradores());

        setarAnexo(historico, data_final);
        setarAnexoCroqui(historico, data_final);

        return historico;
    }

    @Override
    public List<Object[]> findQueryHistory(Long id) {
        Query historyQuery = getEntityManager()
                .createNativeQuery("SELECT * FROM " + Imovel.class.getSimpleName() + "_hist"
                + " WHERE data_final IS NOT NULL AND id = " + id
                + " ORDER BY codigo ASC");

        return historyQuery.getResultList();
    }

    public void setarProprietariosImovel(Long imovel_id, Imovel historico, Date data_final) {
        String sql = "SELECT proprietarios_id "
                + "FROM " + Imovel.class.getSimpleName().toLowerCase() + "_" + Proprietario.class.getSimpleName().toLowerCase() + "_hist "
                + "WHERE imovel_id = " + imovel_id;

        SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

        if (this.atual.getDataAtualizacao() != null) {
            sql += " AND data_final > '" + data_final + "' "
                    + "AND data_final < '" + formato.format(this.atual.getDataAtualizacao()) + "' ";
        } else {
            sql += "AND data_final IS NULL";
        }

        Query historyQuery = getEntityManager().createNativeQuery(sql);
        List<Long> proprietariosIds = historyQuery.getResultList();
        List<Proprietario> proprietarios = new ArrayList<Proprietario>();

        for (Long idProprietario : proprietariosIds) {
            proprietarios.add(proprietarioServico.find(idProprietario));
        }

        if (!proprietarios.isEmpty()) {
            historico.setProprietarios(proprietarios);
        }
    }

    private void setarCaracterizacao(Imovel historico, Object object) {

        if (object != null) {
            for (Caracterizacao caracterizacao : Caracterizacao.values()) {
                if (caracterizacao.name().equals((String) object)) {
                    historico.setCaracterizacao(caracterizacao);
                }
            }
        }
    }

    private void setarCobertura(Imovel historico, Object object) {

        if (object != null) {
            for (Cobertura cobertura : Cobertura.values()) {
                if (cobertura.name().equals((String) object)) {
                    historico.setCobertura(cobertura);
                }
            }
        }
    }

    private void setarComando(Imovel historico, Object object) {

        if (object != null) {
            for (Comando comando : Comando.values()) {
                if (comando.name().equals((String) object)) {
                    historico.setComando(comando);
                }
            }
        }
    }

    private void setarComposicaoFamiliar(Imovel historico, Object object) {
//
//        if (object != null) {
//            for (ComposicaoFamiliar composicao : ComposicaoFamiliar.values()) {
//                if (composicao.name().equals((String) object)) {
//                    historico.setComposicaoFamiliar(composicao);
//                }
//            }
//        }
    }

    private void setarDominioTerra(Imovel historico, Object object) {

        if (object != null) {
            for (DominioTerra dominio : DominioTerra.values()) {
                if (dominio.name().equals((String) object)) {
                    historico.setDominioTerra(dominio);
                }
            }
        }
    }

    private void setarEstadoConservacao(Imovel historico, Object object) {

        if (object != null) {
            for (EstadoConservacao conservacao : EstadoConservacao.values()) {
                if (conservacao.name().equals((String) object)) {
                    historico.setEstadoConservacao(conservacao);
                }
            }
        }
    }

    private void setarEstrutura(Imovel historico, Object object) {

        if (object != null) {
            for (Estrutura estrutura : Estrutura.values()) {
                if (estrutura.name().equals((String) object)) {
                    historico.setEstrutura(estrutura);
                }
            }
        }
    }

    private void setarFachada(Imovel historico, Object object) {

        if (object != null) {
            for (Fachada fachada : Fachada.values()) {
                if (fachada.name().equals((String) object)) {
                    historico.setFachada(fachada);
                }
            }
        }
    }

    private void setarLocalizacao(Imovel historico, Object object) {

        if (object != null) {
            for (FatorLocalizacao fator : FatorLocalizacao.values()) {
                if (fator.name().equals((String) object)) {
                    historico.setLocalizacao(fator);
                }
            }
        }
    }

    private void setarForro(Imovel historico, Object object) {

        if (object != null) {
            for (Forro forro : Forro.values()) {
                if (forro.name().equals((String) object)) {
                    historico.setForro(forro);
                }
            }
        }
    }

    private void setarInstalacaoSanitaria(Imovel historico, Object object) {

        if (object != null) {
            for (InstSanitaria instalacao : InstSanitaria.values()) {
                if (instalacao.name().equals((String) object)) {
                    historico.setInstSanitaria(instalacao);
                }
            }
        }
    }

    private void setarInstalacaoEletrica(Imovel historico, Object object) {

        if (object != null) {
            for (InstalacoesEletricas eletrica : InstalacoesEletricas.values()) {
                if (eletrica.name().equals((String) object)) {
                    historico.setInstalacoesEletricas(eletrica);
                }
            }
        }
    }

    private void setarOcupacao(Imovel historico, Object object) {

        if (object != null) {
            for (Ocupacao ocupacao : Ocupacao.values()) {
                if (ocupacao.name().equals((String) object)) {
                    historico.setOcupacao(ocupacao);
                }
            }
        }
    }

    private void setarPatrimonio(Imovel historico, Object object) {

        if (object != null) {
            for (Patrimonio patrimonio : Patrimonio.values()) {
                if (patrimonio.name().equals((String) object)) {
                    historico.setPatrimonio(patrimonio);
                }
            }
        }
    }

    private void setarPedologia(Imovel historico, Object object) {

        if (object != null) {
            for (Pedologia pedologia : Pedologia.values()) {
                if (pedologia.name().equals((String) object)) {
                    historico.setPedologia(pedologia);
                }
            }
        }
    }

    private void setarPiso(Imovel historico, Object object) {

        if (object != null) {
            for (Piso piso : Piso.values()) {
                if (piso.name().equals((String) object)) {
                    historico.setPiso(piso);
                }
            }
        }
    }

    private void setarPosicao(Imovel historico, Object object) {

        if (object != null) {
            for (Posicao posicao : Posicao.values()) {
                if (posicao.name().equals((String) object)) {
                    historico.setPosicao(posicao);
                }
            }
        }
    }

    private void setarRendaFamiliar(Imovel historico, Object object) {

//        if (object != null) {
//            for (RendaFamiliar renda : RendaFamiliar.values()) {
//                if (renda.name().equals((String) object)) {
//                    historico.setRendaFamiliar(renda);
//                }
//            }
//        }
    }

    private void setarRevestimentoExterno(Imovel historico, Object object) {

        if (object != null) {
            for (RevExterno revestimento : RevExterno.values()) {
                if (revestimento.name().equals((String) object)) {
                    historico.setRevExterno(revestimento);
                }
            }
        }
    }

    private void setarSituacaoTerreno(Imovel historico, Object object) {

        if (object != null) {
            for (SituacaoTerreno situacao : SituacaoTerreno.values()) {
                if (situacao.name().equals((String) object)) {
                    historico.setSituacaoTerreno(situacao);
                }
            }
        }
    }

    private void setarTipoConstrucao(Imovel historico, Object object) {

        if (object != null) {
            for (TipoConstrucao tipo : TipoConstrucao.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setTipoConstrucao(tipo);
                }
            }
        }
    }

    private void setarTipoDocumentoImovel(Imovel historico, Object object) {

        if (object != null) {
            for (TipoDocumentoImovel tipo : TipoDocumentoImovel.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setTipoDocumentoImovel(tipo);
                }
            }
        }
    }

    private void setarTopografia(Imovel historico, Object object) {

        if (object != null) {
            for (Topografia topografia : Topografia.values()) {
                if (topografia.name().equals((String) object)) {
                    historico.setTopografia(topografia);
                }
            }
        }
    }

    private void setarTipoPropriedade(Imovel historico, Object object) {

        if (object != null) {
            for (TipoPropriedade tipo : TipoPropriedade.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setTipoPropriedade(tipo);
                }
            }
        }
    }

    private void setarTipoImovel(Imovel historico, Object object) {

        if (object != null) {
            for (TipoImovel tipo : TipoImovel.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setTipoImovel(tipo);
                }
            }
        }
    }

    private void setarTipoTitulo(Imovel historico, Object object) {

        if (object != null) {
            for (TipoTitulo tipo : TipoTitulo.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setTipoTitulo(tipo);
                }
            }
        }
    }

    private void setarUsoImovel(Imovel historico, Object object) {

        if (object != null) {
            for (UsoImovel tipo : UsoImovel.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setUsoImovel(tipo);
                }
            }
        }
    }

    private void setarUtilizacao(Imovel historico, Object object) {

        if (object != null) {
            for (Utilizacao tipo : Utilizacao.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setUtilizacao(tipo);
                }
            }
        }
    }

    private void setarVinculoTitularRip(Imovel historico, Object object) {

        if (object != null) {
            for (Vinculo tipo : Vinculo.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setVinculoTitularRip(tipo);
                }
            }
        }
    }

    private void setarDimensoes(Imovel historico, Object object) {

        if (object != null) {
            Dimensao dimensao = dimensaoServico.find((Long) object);
            historico.setDimensoes(dimensao);
        }
    }

    private void setarEnderecoCorrespondencia(Imovel historico, Object object) {

        if (object != null) {
            Endereco endereco = enderecoServico.find((Long) object);
            historico.setEnderecoCorrespondencia(endereco);
        }
    }

    private void setarEnderecoImovel(Imovel historico, Object object) {

        if (object != null) {
            Endereco endereco = enderecoServico.find((Long) object);
            historico.setEnderecoImovel(endereco);
        }
    }

    private void setarImovel(Imovel historico, Object object) {

        if (object != null) {
            historico.setImovel(new Imovel());
            historico.getImovel().setId((Long) object);
        }
    }

    private void setarSituacaoImovel(Imovel historico, Object object) {

        if (object != null) {
            for (SituacaoImovel tipo : SituacaoImovel.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setSituacaoImovel(tipo);
                }
            }
        }
    }

    private void setarFatorLocalizacao(Imovel historico, Object object) {

        if (object != null) {
            for (FatorLocalizacao tipo : FatorLocalizacao.values()) {
                if (tipo.name().equals((String) object)) {
                    historico.setLocalizacao(tipo);
                }
            }
        }
    }

    private void setarAnexo(Imovel historico, Date data_final) {

        String sql = "SELECT id "
                + "FROM " + Anexo.class.getSimpleName().toLowerCase() + "_hist "
                + "WHERE imovel_id = " + this.atual.getId();

        SimpleDateFormat formato = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

        if (this.atual.getDataAtualizacao() != null) {
            sql += " AND data_final > '" + data_final + "' "
                    + "AND data_final < '" + formato.format(this.atual.getDataAtualizacao()) + "'";
        }

        sql += " AND data_final IS NULL";

        Query query = getEntityManager().createNativeQuery(sql);
        List<Long> ids = query.getResultList();

        if (ids != null && !ids.isEmpty()) {

            List<Anexo> anexos = new ArrayList<Anexo>();

            for (Long id : ids) {
                anexos.add(anexoServico.find(id));
            }

            historico.setAnnex(anexos);

        } else {
            historico.setAnnex(null);
        }
    }

    private void setarAnexoCroqui(Imovel historico, Date data_final) {

        String sql = "SELECT id "
                + "FROM " + Anexo.class.getSimpleName().toLowerCase() + "_hist "
                + "WHERE imovelcroqui_id = " + this.atual.getId();

        if (this.atual.getDataAtualizacao() != null) {
            sql += " AND (data_final > '" + data_final + "' "
                    + "AND data_final < '" + this.atual.getDataAtualizacao() + "') ";
        } else {
            sql += " AND data_final IS NULL";
        }

        Query query = getEntityManager().createNativeQuery(sql);
        List<Long> ids = query.getResultList();

        if (ids != null && !ids.isEmpty()) {

            List<Anexo> anexos = new ArrayList<Anexo>();

            for (Long id : ids) {
                anexos.add(anexoServico.find(id));
            }

            historico.setAnnexCroquis(anexos);

        } else {
            historico.setAnnexCroquis(null);
        }
    }
}
